/**
 * \file mere.c
 * \author H4201
 */

/*MODULES USED*/
#include <sys/stat.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

#include "mere.h"
#include "reception_linux.h"
#include "../reseau/envoi.h"
#include "../erreur/erreurs.h"
#include "../messages/log.h"
#include "../utils/utils.h"
#include "../interface/partage_simu.h"
#include "../interface/messqueue.h"
#include "../interface/mutexpartage.h"
#include "../ChaineCond/init_functions.h"

/*GLOBAL VARIABLES*/

/**
 * Attribut de mqueue.
 */
static struct mq_attr attrmq;

/**
 * Attribut de thread.
 */
static pthread_attr_t attr;

/**
 * Paramètre de thread.
 */
static struct sched_param param;

/*EXPORTED FUNCTIONS*/

/**
 * Fonction qui sert de point d'entré au thread "Mere"
 * \param parameter inutilisé ici
 */
void* mere(void *parameter) {
    
    //initialisation des sémaphores partagés entre le noyau et la chaine de conditionnement
    sem_init(&sem_carton_absent, 0, 0);
    sem_init(&sem_err_imprim,0, 0);
    sem_init(&sem_palette_absente, 0, 0);
    sem_init(&sem_err_embal, 0, 0);
	sem_init(&sem_err_timeout, 0, 0);
    
    // définition des attributs d'une file de messages
    attrmq.mq_flags = 0;
    attrmq.mq_maxmsg = 1000;
    attrmq.mq_msgsize = sizeof(message_t);
    attrmq.mq_curmsgs = 0;
    
    //initialisation des files de messages paratagées entre le noyau et la chaine de conditionnement
    mqd_t bal_messages = mq_open(BAL_MESSAGES_NAME, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG, &attrmq);
    mqd_t bal_erreurs = mq_open(BAL_ERREURS_NAME, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG, &attrmq);
    mqd_t bal_retrait = mq_open(BAL_RETRAIT_NAME, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG, &attrmq);
    
    //initialisation des files des messages locales
    mqd_t bal_superviseur = mq_open(BAL_SUPERVISEUR_NAME, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG, &attrmq);    
    
    
    
    //Création des différents threads
    
    pthread_t ecritureJournalThread, receptionLinuxThread, erreursThread;
    
    int err;
    pthread_attr_init (& attr);
    
    if ((err = pthread_attr_setschedpolicy(& attr, SCHED_FIFO)) != 0) {
        fprintf(stderr, "setschedpolicy: %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    if ((err = pthread_attr_setinheritsched(& attr, PTHREAD_EXPLICIT_SCHED)) != 0) {
        fprintf(stderr, "setinheritsched: %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    //Création du thread "Réception Linux"
    param.sched_priority = 1;
    
    if ((err = pthread_attr_setschedparam(& attr, & param)) != 0) {
        fprintf(stderr, "setschedparam: %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    if ((err = pthread_create(&receptionLinuxThread, & attr, &reception_linux, parameter)) != 0) {
        fprintf(stderr, "pthread_create Reception Linux : %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    //Création du thread "Ecriture journal"
    param.sched_priority = 1;
    
    if ((err = pthread_attr_setschedparam(& attr, & param)) != 0) {
        fprintf(stderr, "setschedparam: %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    if ((err = pthread_create(&ecritureJournalThread, & attr, &ecriture_journal, NULL)) != 0) {
        fprintf(stderr, "pthread_create Ecriture Journal : %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
        
    //Création du thread "Erreurs"
    param.sched_priority = 99;
    
    if ((err = pthread_attr_setschedparam(& attr, & param)) != 0) {
        fprintf(stderr, "setschedparam: %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    if ((err = pthread_create(&erreursThread, & attr, &erreurs, NULL)) != 0) {
        fprintf(stderr, "pthread_create Erreurs : %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
	
    init_chaine_cond();
    
    //attente de fin des threads
    pthread_join(erreursThread, NULL);
    pthread_join(receptionLinuxThread, NULL);
    pthread_join(ecritureJournalThread, NULL);
    
    
    //fermeture des files de messages paratagées entre le noyau et la chaine de conditionnement
    mq_close(bal_messages);
    mq_unlink(BAL_MESSAGES_NAME);
    mq_close(bal_erreurs);
    mq_unlink(BAL_ERREURS_NAME);
    mq_close(bal_retrait);
    mq_unlink(BAL_RETRAIT_NAME);
    mq_close(bal_superviseur);
    mq_unlink(BAL_SUPERVISEUR_NAME);
    
    detruire_objets_chaine_cond();
    
    //destruction des sémaphores partagés entre le noyau et la chaine de conditionnement
    sem_destroy(&sem_carton_absent);
    sem_destroy(&sem_err_imprim);
    sem_destroy(&sem_palette_absente);
    sem_destroy(&sem_err_embal);
    sem_destroy(&sem_err_timeout);

    
    return 0; 
}

/**
 * Sert à créer le thread "Envoi Linux"
 * \return Identifiant du thread "Envoi Linux"
 */
pthread_t lancer_thread_envoi() {
    pthread_t envoiLinuxThread;
    int err;
    
    //Création du thread "Envoi Linux"
    param.sched_priority = 1;
    
    if ((err = pthread_attr_setschedparam(& attr, & param)) != 0) {
        fprintf(stderr, "setschedparam: %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    if ((err = pthread_create(&envoiLinuxThread, & attr, &envoi_linux, NULL)) != 0) {
        fprintf(stderr, "pthread_create Envoi Linux : %s\n", strerror(err));
        exit(EXIT_FAILURE);
    }
    
    return envoiLinuxThread;
}
